<script setup>
import {computed, onMounted, reactive, useSlots, watch} from 'vue'
import {randomCode} from '@/utils/common/string.js'
import {JBoltApi} from '@/service/request'
import {getServiceEnvConfig} from '~/.env-config'
import {useMessage} from 'naive-ui' // 导入消息组件

const message = useMessage() // 初始化消息组件
const slots = useSlots()
const props =
    defineProps({
        /** 是否只用于展示文件列表，不上传 */
        /** 最大允许上传文件数 */
        max: {
            type: Number,
            default: Infinity // 默认不限制
        },
        /** 最大允许上传文件大小(MB) */
        maxSize: {
            type: Number,
            default: 10 // 默认10MB
        },
        onlyShow: {
            type: Boolean,
            default: false
        },
        /**上传到哪里，暂时只支持七牛 */
        uploadTo: {
            type: String,
            default: undefined
        },
        /** 使用哪个七牛账号上传，不传则使用默认的，但需要后台配置默认账号 */
        qiniuSn: {
            type: String,
            default: undefined
        },
        /**上传到服务器的路径，支持动态参数，参考 src/utils/common/file.ts中generatePath说明。 */
        savePath: {
            type: String,
            default: undefined
        },
        /** 绑定的数据 */
        modelValue: {
            type: [Array, String],
            required: true
        },
        /** 上传的文件地址是否join成一个字符串，false代表不join返回数组结构，字符串代表join使用的字符，value返回的是join后的一个完整字符串*/
        valueJoin: {
            type: [Boolean, String],
            default: ','
        },
        showFileList: {
            type: Boolean,
            default: true
        }
    })

const emit = defineEmits(['update:modelValue', 'loadFiles'])

const uploadTo = computed(() => {
    const {defaultUploadTo} = getServiceEnvConfig(import.meta.env)
    return props.uploadTo || defaultUploadTo
})

const qiniuSn = computed(() => {
    const {defaultQiniuSn} = getServiceEnvConfig(import.meta.env)
    return props.qiniuSn || defaultQiniuSn
})

const state = reactive({
    fileList: [],
    files: []
})

watch(
    () => props.modelValue,
    () => {
        if (state.fileList.length == 0) {
            syncFileListByModelValue()
        }
    }
)

// 检查文件大小的函数
const checkFileSize = (file) => {
    const maxSizeBytes = props.maxSize * 1024 * 1024 // 转换为字节
    if (file.size > maxSizeBytes) {
        message.error(`文件 "${file.name}" 超过最大限制 ${props.maxSize}MB，请选择较小的文件`)
        return false
    }
    return true
}

async function toUpload({
                            file,
                            onFinish,
                            onError,
                            onProgress
                        }) {

    // 检查文件大小
    if (!file.file || !checkFileSize(file.file)) {
        onError()
        return
    }

    let url = null
    try {
        switch (uploadTo.value) {
            case 'qiniu':
                url = await JBoltApi.uploadToQiniu(
                    file.file,
                    props.savePath,
                    qiniuSn.value ?? '',
                    ({percent}) => {
                        onProgress({percent})
                    }
                )
                break
            case 'server':
                url = await JBoltApi.uploadToServer(
                    file.file,
                    props.savePath,
                    ({percent}) => {
                        onProgress({percent})
                    }
                )
                break
            default:
                throw new Error('不支持的上传类型')
        }
        file.url = url

        console.log('file', file)
        onFinish()

        let fileData = {
            fileName: file.file.name,
            fileType: url.substring(url.lastIndexOf('.') + 1),
            filePath: url,
            fileSize: parseFloat((file.file.size / 1024).toFixed(2))
        }

        state.files.push(fileData)
        emit('loadFiles', state.files)
        state.files = []


        const value = state.fileList
            .filter((item) => item.status == 'finished')
            .map((item) => item.url)


        if (props.valueJoin) {
            console.log('lll', value.join(props.valueJoin))
            emit('update:modelValue', value.join(props.valueJoin))
        } else {
            console.log('ccc', value)
            emit('update:modelValue', value)
        }


    } catch (e) {
        onError()
    }
}

function removeFile({file}) {
    const value = state.fileList
        .filter((item) => item.status == 'finished' && item.id != file.id)
        .map((item) => item.url)
    if (props.valueJoin) {
        emit('update:modelValue', value.join(props.valueJoin))
    } else {
        emit('update:modelValue', value)
    }
}

function syncFileListByModelValue() {
    let value = props.modelValue
    if (typeof value == 'string' && props.valueJoin) {
        value = value.split(props.valueJoin)
    } else if (typeof value == 'string' && !props.valueJoin) {
        throw new Error('valueJoin为false时，modelValue的值不能是字符串')
    }
    state.fileList = value.map((url) => {
        return {
            id: randomCode(8),
            name: url.substring(url.lastIndexOf('/') + 1),
            status: 'finished',
            url: url
        }
    })
}

onMounted(() => {
    if (props.modelValue) {
        syncFileListByModelValue()
    }
})

defineExpose({
    getFileList: () => state.files
})
</script>

<template>
    <n-upload
        v-model:file-list="state.fileList"
        :max="max"
        :custom-request="toUpload"
        :class="{ notupload: props.onlyShow }"
        @remove="removeFile"
        :showFileList="props.showFileList"
    >
        <template v-for="(_item, key) in slots" :key="key" #[key]="data">
            <slot :name="key" v-bind="data ?? {}"/>
        </template>
    </n-upload>
</template>

<style scoped>
.notupload :deep(.n-upload-trigger) {
    display: none;
}
</style>